#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../include/utils.h"

/* 默认的自动增长策略 */
static size_t C_UTILS_API __array_auto_increment_policy( array * arr )
{
	size_t inc = arr->max_count / 3;
	if ( inc == 0U ) inc = 1;
	return inc;
}

/* 数组增长 */
static size_t __array_increment( array * arr, size_t inc )
{
	arr->max_count += inc + arr->increment(arr);
	arr->base = (unsigned char *)realloc( arr->base, arr->max_count * arr->elem_size );
	return arr->max_count;
}

/* 创建一个max_count个元素,每个元素elem_size字节的数组,返回字节数 */
C_UTILS_IMPL_API(int) array_create( array * arr, size_t max_count, size_t elem_size, fn_array_increment increment/* = NULL*/ )
{
	arr->count = 0;
	arr->max_count = max_count;
	arr->elem_size = elem_size;
	arr->increment = increment != NULL ? increment : __array_auto_increment_policy;
	/* 分配内存 */
	arr->base = (unsigned char *)calloc( max_count, elem_size );
	return max_count * elem_size;
}

/* 销毁一个数组 */
C_UTILS_IMPL_API(void) array_destroy( array * arr )
{
	free(arr->base);
	memset( arr, 0, sizeof(array) );
}

/* 释放多余 */
C_UTILS_IMPL_API(void) array_free_extra( array * arr )
{
	arr->base = (unsigned char *)realloc( arr->base, arr->count * arr->elem_size );
	arr->max_count = arr->count;
}

/* 增加元素,返回索引 */
C_UTILS_IMPL_API(int) array_add( array * arr, void * elem, size_t count )
{
	int index = arr->count;
	while ( arr->max_count < arr->count + count )
		__array_increment( arr, count );

	memcpy( arr->base + index * arr->elem_size, elem, count * arr->elem_size );
	arr->count += count;
	return index;
}

/* 从index开始删除count个元素,返回当前个数 */
C_UTILS_IMPL_API(int) array_del( array * arr, int index, int count )
{
	if ( count > 0 && index + count <= (int)arr->count )
	{
		memmove(
			arr->base + index * arr->elem_size,
			arr->base + ( index + count ) * arr->elem_size,
			( arr->count - ( index + count ) ) * arr->elem_size
		);
		arr->count -= count;
	}
	else if ( count == -1 )
	{
		arr->count = index;
	}

	return arr->count;
}

/* 获取元素 */
C_UTILS_IMPL_API(void *) array_get( array * arr, int index )
{
	return arr->base + index * arr->elem_size;
}

/* 设置元素 */
C_UTILS_IMPL_API(void) array_set( array * arr, int index, void * elem )
{
	memcpy( arr->base + index * arr->elem_size, elem, 1 * arr->elem_size );
}

C_UTILS_IMPL_API(array) array_clone( array * arr )
{
	array res = *arr;
	res.max_count = res.count;
	res.base = (unsigned char *)malloc( res.count * res.elem_size );
	memcpy( res.base, arr->base, res.count * res.elem_size );
	return res;
}

C_UTILS_IMPL_API(array) array_clone_direct( void * p, size_t count, size_t elem_size )
{
	array res;
	res.count = count;
	res.max_count = count;
	res.elem_size = elem_size;
	res.increment = __array_auto_increment_policy;
	res.base = (unsigned char *)malloc( res.count * res.elem_size );
	if ( p != NULL ) memcpy( res.base, p, res.count * res.elem_size );
	return res;
}

/* -----------------------------------------------------------------------------------
   xstring methods
   ----------------------------------------------------------------------------------- */

/* ansi_string增长 */
static size_t __ansi_string_increment( ansi_string * str, size_t inc )
{
	size_t inc_auto = str->max_count / 3;
	inc_auto = inc_auto == 0U ? 1 : inc_auto;
	str->max_count += inc + inc_auto;
	str->val = (char *)realloc( str->val, str->max_count * sizeof(char) );
	return str->max_count;
}

/* 创建一个ansi字符串,设定一个最大长度 */
C_UTILS_IMPL_API(int) ansi_string_create( ansi_string * str, size_t max_length )
{
	str->length = 0;
	str->count = 1; /* 至少包含NUL符 */
	str->max_count = max_length + 1;
	str->val = (char *)calloc( str->max_count, sizeof(char) );
	memset( str->val, 0, str->count * sizeof(char) );
	return str->max_count * sizeof(char);
}
/* 销毁一个ansi字符串 */
C_UTILS_IMPL_API(void) ansi_string_destroy( ansi_string * str )
{
	free(str->val);
	memset( str, 0, sizeof(ansi_string) );
}

C_UTILS_IMPL_API(void) ansi_string_free_extra( ansi_string * str )
{
	str->val = (char *)realloc( str->val, str->count * sizeof(char) );
	str->max_count = str->count;
}

/* 字符串赋值,返回长度 */
C_UTILS_IMPL_API(int) ansi_string_assign( ansi_string * str, char * s )
{
	size_t len;
	if ( s == NULL ) s = "";
	len = strlen(s);
	while ( str->max_count < 1 + len )
		__ansi_string_increment( str, len );

	memcpy( str->val, s, ( len + 1 ) * sizeof(char) );
	str->length = len;
	str->count = str->length + 1;
	return str->length;
}

C_UTILS_IMPL_API(int) ansi_string_append( ansi_string * str, char * s )
{
	size_t len;
	if ( s == NULL ) s = "";
	len = strlen(s);
	while ( str->max_count < str->count + len )
		__ansi_string_increment( str, len );
	
	memcpy( str->val + str->length, s, ( len + 1 ) * sizeof(char) );
	str->length += len;
	str->count = str->length + 1;
	return str->length;
}

C_UTILS_IMPL_API(int) ansi_string_append_str( ansi_string * str, ansi_string * s )
{
	return ansi_string_append( str, s->val );
}

C_UTILS_IMPL_API(int) ansi_string_erase( ansi_string * str, int index, int length )
{
	if ( length > 0 && length + index <= (int)str->length )
	{
		memmove(
			str->val + index,
			str->val + ( index + length ),
			( 1 + ( str->length - ( index + length ) ) ) * sizeof(char)
		);
		str->length -= length;
		str->count = str->length + 1;
	}
	else if ( length == -1 )
	{
		str->val[index] = 0;
		str->length = index;
		str->count = str->length + 1;
	}
	return str->length;
}


/* ----------------------------------------------------------------------------- */
/* unicode_string增长 */
static size_t __unicode_string_increment( unicode_string * str, size_t inc )
{
	size_t inc_auto = str->max_count / 3;
	inc_auto = inc_auto == 0U ? 1 : inc_auto;
	str->max_count += inc + inc_auto;
	str->val = (wchar_t *)realloc( str->val, str->max_count * sizeof(wchar_t) );
	return str->max_count;
}

C_UTILS_IMPL_API(int) unicode_string_create( unicode_string * str, size_t max_length )
{
	str->length = 0;
	str->count = 1;
	str->max_count = max_length + 1;
	str->val = (wchar_t *)calloc( str->max_count, sizeof(wchar_t) );
	memset( str->val, 0, str->count * sizeof(wchar_t) );
	return str->max_count * sizeof(wchar_t);
}

C_UTILS_IMPL_API(void) unicode_string_destroy( unicode_string * str )
{
	free(str->val);
	memset( str, 0, sizeof(unicode_string) );
}

C_UTILS_IMPL_API(void) unicode_string_free_extra( unicode_string * str )
{
	str->val = (wchar_t *)realloc( str->val, str->count * sizeof(wchar_t) );
	str->max_count = str->count;
}

C_UTILS_IMPL_API(int) unicode_string_assign( unicode_string * str, wchar_t * s )
{
	size_t len;
	if ( s == NULL ) s = L"";
	len = wcslen(s);
	while ( str->max_count < 1 + len )
		__unicode_string_increment( str, len );
	
	memcpy( str->val, s, ( len + 1 ) * sizeof(wchar_t) );
	str->length = len;
	str->count = str->length + 1;
	return str->length;
}

C_UTILS_IMPL_API(int) unicode_string_append( unicode_string * str, wchar_t * s )
{
	size_t len;
	if ( s == NULL ) s = L"";
	len = wcslen(s);
	while ( str->max_count < str->count + len )
		__unicode_string_increment( str, len );
	
	memcpy( str->val + str->length, s, ( len + 1 ) * sizeof(wchar_t) );
	str->length += len;
	str->count = str->length + 1;
	return str->length;
}

C_UTILS_IMPL_API(int) unicode_string_append_str( unicode_string * str, unicode_string * s )
{
	return unicode_string_append( str, s->val );
}

C_UTILS_IMPL_API(int) unicode_string_erase( unicode_string * str, int index, int length )
{
	if ( length > 0 && length + index <= (int)str->length )
	{
		memmove(
			str->val + index,
			str->val + ( index + length ),
			( 1 + ( str->length - ( index + length ) ) ) * sizeof(wchar_t)
		);
		str->length -= length;
		str->count = str->length + 1;
	}
	else if ( length == -1 )
	{
		str->val[index] = 0;
		str->length = index;
		str->count = str->length + 1;
	}
	return str->length;
}

union
{
	struct
	{
		byte b0;
		byte b1;
		byte b2;
	} field8;
	struct
	{
		byte b0:6;
		byte b1:6;
		byte b2:6;
		byte b3:6;
	} field6;
} v;

/*
		v.field8.b0 = buf[i * 3 + 0];
		v.field8.b1 = buf[i * 3 + 1];
		v.field8.b2 = buf[i * 3 + 2];
		printf("byte{%u %u %u} ", v.field8.b0, v.field8.b1, v.field8.b2 );
		printf("%u %u %u %u, ", v.field6.b0, v.field6.b1, v.field6.b2, v.field6.b3 );
*/

static char base64chars[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

C_UTILS_IMPL_API(ansi_string) base64_encode( byte * buf, size_t size )
{
	int n, m, i;
	byte b0, b1, b2;
	char code[5] = "";
	ansi_string result;
	ansi_string_create( &result, 64 );
	n = size / 3;
	m = size % 3;
	for ( i = 0; i < n; ++i )
	{
		b0 = buf[i * 3 + 0];
		b1 = buf[i * 3 + 1];
		b2 = buf[i * 3 + 2];
		code[0] = base64chars[b0 >> 2];
		code[1] = base64chars[ ( ( b0 & 3 ) << 4 ) | ( ( b1 & 0xF0 ) >> 4 ) ];
		code[2] = base64chars[ ( ( b1 & 0xF ) << 2 ) | ( ( b2 & 0xC0 ) >> 6 ) ];
		code[3] = base64chars[b2 & 0x3F];
		ansi_string_append( &result, code );
	}
	switch ( m )
	{
	case 2:
		{
			b0 = buf[i * 3 + 0];
			b1 = buf[i * 3 + 1];
			b2 = 0;
			code[0] = base64chars[b0 >> 2];
			code[1] = base64chars[ ( ( b0 & 3 ) << 4 ) | ( ( b1 & 0xF0 ) >> 4 ) ];
			code[2] = base64chars[ ( ( b1 & 0xF ) << 2 ) | ( ( b2 & 0xC0 ) >> 6 ) ];
			code[3] = '=';
			ansi_string_append( &result, code );
		}
		break;
	case 1:
		{
			b0 = buf[i * 3 + 0];
			b1 = 0;
			b2 = 0;
			code[0] = base64chars[b0 >> 2];
			code[1] = base64chars[ ( ( b0 & 3 ) << 4 ) | ( ( b1 & 0xF0 ) >> 4 ) ];
			code[2] = '=';
			code[3] = '=';

			ansi_string_append( &result, code );
		}
		break;
	}

	return result;
}

C_UTILS_IMPL_API(array_byte) base64_decode( ansi_string * str )
{
	array_byte result;
	

	return result;
}
